﻿/*
	Copyright (C) 2019 Zongming Liu <1849059316@qq.com>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.
	
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	
	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "Node.h"
#include "../base/Matrix.h"
#include "../win32/ApplicationView.h"
#include "../base/Constant.h"
#include "../render/Camera.h"
#include "../base/Debuger.h"
#include "../action/ActionManager.h"
#include "../action/Action.h"
#include "../base/GameWorld.h"

#include <algorithm>

namespace SkyEngine2d
{
	
	Node::Node(Node* parent)
		: Object<Node>(parent)
		, m_visible(true)
		, m_localZOrder(0)
		, m_globalZOrder(0)
		, m_position(0, 0)
		, m_rotation(0)
		, m_scalingX(1.0f)
		, m_scalingY(1.0f)
		, m_isChangeTransforMat(true)
		, m_camera(nullptr)
		, m_actionManager(nullptr)
		, m_isNeedSort(true)
		, m_gameWorld(nullptr)
		, m_running(true)
	{
		if (m_parent)
		{
			m_parent->m_isNeedSort = true;
		}
		m_gameWorld = GameWorld::getInstance();
		m_actionManager = m_gameWorld->getActionManger();
	}
	
	bool Node::init()
	{
		if (!Object<Node>::init())
		{
			return false;
		}
	
	
		auto parent = m_parent;
		if (parent)
		{
			this->setCamera(parent->getCamera());
		}
		else
		{
			this->setCamera(Camera::getDefultCamera());
		}
	
		return true;
	}
	
	
	Node::~Node()
	{
		if (m_parent)
		{
			m_parent->m_isNeedSort = true;
		}
	}
	
	
	void Node::draw(IRender* render, const Matrix4X4& transform)
	{
	
	}
	
	void Node::visit(IRender* render, bool parent_change_transfrom_mat)
	{
		if (!m_visible)
		{
			return;
		}
	
		//更新矩阵
		this->updateTransformMat(parent_change_transfrom_mat);
		//更新相机
		this->getCamera()->updataCarme();
	
		if (!m_childrenList.empty())
		{
			if (m_isNeedSort)
			{
				m_childrenList.sort([](Node * a, Node * b) {
					return a->getLocalZOrder() < b->getLocalZOrder(); }
				);
	
				m_isNeedSort = false;
			}
	
			auto iter = m_childrenList.begin();
	
			//先渲染 z 小与 0 的
			for (; iter != m_childrenList.end(); ++iter)
			{
				auto node = (*iter);
				if (node->m_localZOrder < 0)
				{
					node->visit(render, isChangeTransformMat()); //TODO 这里有BUG 父节点更新 在updateTransformMat 永远为false
				}
				else
				{
					break;
				}
			}
	
			//渲染自身
			this->draw(render, m_transformMat);
	
			//渲染大于0的
			for (; iter != m_childrenList.end(); ++iter)
			{
				(*iter)->visit(render, isChangeTransformMat());
			}
	
		}
		else
		{
			this->draw(render, m_transformMat);
		}
	}
	
	
	Node* Node::create(Node* parent)
	{
		auto p = makeNodePtr(parent);
		if (p && p->init())
		{
			return p;
		}
		else
		{
			if (parent)
			{
				parent->removeChildren(p);
			}
		}
		return nullptr;
	}
	
	void Node::setLoacalZOrder(int32_t z)
	{
		m_localZOrder = z;
	
		if (m_parent)
		{
			m_parent->m_isNeedSort = true;
		}
	}
	
	void Node::setGlobalZOrder(int32_t z)
	{
		m_globalZOrder = z;
	}
	
	
	void Node::movePosition(float dt_x, float dt_y)
	{
		Vector2 pos(m_position.x + dt_x, m_position.y + dt_y);
	
		this->setPosition(pos);
	}
	
	void Node::movePosition(const Vector2 & dt_pos)
	{
		this->movePosition(dt_pos.x, dt_pos.y);
	}
	
	void Node::setPosition(float x, float y)
	{
		Vector2 pos(x, y);
	
		//调用监听
		if (m_onPositionChangeBefore)
		{
			(*m_onPositionChangeBefore)(pos);
		}
	
		Vector2 temp = m_position;
	
		m_position = pos;
		changeTransformMat();
	
		//调用监听
		if (m_onPositionChangeAfter)
		{
			(*m_onPositionChangeAfter)(temp, m_position);
		}
	
	}
	
	void Node::setPosition(const Vector2 & new_pos)
	{
		this->setPosition(new_pos.x, new_pos.y);
	}
	
	void Node::setRotationR(float radian)
	{
	
		m_rotation = radian; changeTransformMat();
	}
	
	void Node::setRotationA(float angle)
	{
		m_rotation = (PI / 180) * angle; changeTransformMat();
	}
	
	void Node::setScalingX(float sx)
	{
		m_scalingX = sx; changeTransformMat();
	}
	
	void Node::setScalingY(float sy)
	{
		m_scalingY = sy; changeTransformMat();
	}
	
	Vector2 Node::getPosition() const
	{
		return m_position;
	}
	
	float Node::getRoattionR() const
	{
		return m_rotation;
	}
	
	float  Node::getRoattionA() const
	{
		return (180 / PI) * m_rotation;
	}
	
	
	float Node::getScalingX() const
	{
		return m_scalingX;
	}
	
	float Node::getScalingY() const
	{
		return m_scalingY;
	}
	
	bool Node::isChangeTransformMat() const
	{
		return m_isChangeTransforMat;
	}
	
	Camera* Node::getCamera() const
	{
		return m_camera;
	}
	
	void Node::setCamera(Camera * c, bool is_recursion/*=true*/)
	{
		m_camera = c;
		if (!is_recursion)
		{
			return;
		}
		for (auto& n : m_childrenList)
		{
			n->setCamera(c);
		}
	}
	
	
	bool Node::runAction(ActionSharedPtr action)
	{
		DebugerAssert(m_actionManager != nullptr, "动画管理器为空.");
	
		if (m_actionManager == nullptr)
		{
			return false;
		}
	
		//TODO 目前  参数3 先按 运行处理    应该按照 当前的运行状态处理 但是 m_running 成员还没设计好 先不使用了 
		m_actionManager->addAction(action, this, false);
	
		return true;
	}
	
	void Node::stopActionByName(const std::wstring & action_name)
	{
		DebugerAssert(m_actionManager != nullptr, "动画管理器为空.");
		if (m_actionManager != nullptr)
		{
			m_actionManager->removeActionByName(action_name, this);
		}
	}
	
	
	ActionSharedPtr Node::getActionByName(const std::wstring & name)
	{
		DebugerAssert(m_actionManager != nullptr, "动画管理器为空.");
		if (m_actionManager != nullptr)
		{
			return m_actionManager->getActionByName(name, this);
		}
		return nullptr;
	}
	
	
	void Node::installListenerAtPosChangeBefore(const std::function<void(Vector2 & future_position)> & call_func)
	{
		if (!m_onPositionChangeBefore)
		{
			m_onPositionChangeBefore = std::make_unique<std::function<void(Vector2 & position)>>();
		}
		*m_onPositionChangeBefore = call_func;
	}
	
	void Node::installListenerAtPosChangeAfter(const std::function<void(const Vector2 & old_pos, const Vector2 & now_pos)> & call_func)
	{
		if (!m_onPositionChangeAfter)
		{
			m_onPositionChangeAfter = std::make_unique<FuncAtPosChangeAfter>();
		}
		*m_onPositionChangeAfter = call_func;
	}
	
	
	Vector2 Node::convertToRenderCoordinate(const Vector2 & v)
	{
		auto size = GameWorld::getInstance()->getAppView()->getViewSize();
		return Vector2(v.x, size.height - v.y);
	}
	
	
	void Node::updateTransformMat(bool prant_transformMat_is_change)
	{
		if (prant_transformMat_is_change || isChangeTransformMat())
		{
			DirectX::XMMATRIX translation = DirectX::XMMatrixTranslation(m_position.x, m_position.y, 0.0f);
			DirectX::XMMATRIX rotationZ = DirectX::XMMatrixRotationZ(m_rotation);
			DirectX::XMMATRIX scale = DirectX::XMMatrixScaling(m_scalingX, m_scalingY, 1.0f);
			DirectX::XMMATRIX parent = getParentTransformMat();
			//计算世界矩阵  父节点矩阵 * 缩放 * 旋转 * 平移
			this->m_transformMat = parent * scale * rotationZ * translation;
			m_isChangeTransforMat = false;
		}
	}
	
	const Matrix4X4& Node::getParentTransformMat() const
	{
		auto p = m_parent;
		if (p)
		{
			return p->m_transformMat;
		}
		//如果没有父节点  则返回一个单位矩阵
		static Matrix4X4 m;
		return m;
	}
	
}
